<template>
    <div class="writeContent">
        <div class="writeBtn">
            <van-button style="width: 100%;border-radius: 16px;border: none; transition: all 0.3s ease;margin-right: 20px;" type="warning" :class="{ active: isActive1 }" @click="cancel">重新开始</van-button>
            <van-button style="width: 100%;background: #15256a;color: #FFF;border-radius: 16px;border: none; transition: all 0.3s ease;" :class="{ active: isActive2 }"
                @click="save">保存图片</van-button>
        </div>
        <div class="writeBox">
            <canvas ref="canvasRef" style="border-radius: 12px;"></canvas>
        </div>
    </div>
</template>
    
<script setup lang="ts">
import { ref, onMounted, computed, onUnmounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showToast, showFailToast, showConfirmDialog, showNotify } from 'vant'


const route = useRoute()
const router = useRouter()

const isActive1 = ref<boolean>(false)
const isActive2 = ref<boolean>(false)

const handleClick = (type: string) => {
    if (type == '1') {
        isActive1.value = !isActive1.value
        setTimeout(() => {
            isActive1.value = !isActive1.value
        }, 100)
    } else if (type == '2') {
        isActive2.value = !isActive2.value
        setTimeout(() => {
            isActive2.value = !isActive2.value
        }, 100)
    }
}

interface IProps {
  /**
   * @description   画布宽度
   * @default       900
   */
  width?: number;
  /**
   * @description   画布高度
   * @default       450
   */
  height?: number;
  /**
   * @description   线宽
   * @default       4
  */
  lineWidth?: number;
  /**
   * @description   线段颜色
   * @default       'red'
  */
  strokeColor?: string;
  /**
   * @description   设置线条两端圆角
   * @default       'round'
  */
  lineCap?: string;
  /**
   * @description   线条交汇处圆角
   * @default       'round'
  */
  lineJoin?: string;
  /**
   * @description   画布背景颜色
   * @default       'transparent'
  */
  bgColor?: string;
  /**
   * @description   true
  */
  showBtn?: boolean;
  /**
  * @description   当保存时的回调, blob为生成的图片bob
  * @default       -
  */
  onSave?: (blob: Blob) => void;
  /**
   * @description   当画布清空时的回调, 参数为画布的上下文对象,可以直接使用canvas的api
   * @default       -
   */
  onClear?: (canvasContext: CanvasRenderingContext2D) => void;
  /**
  * @description   当画布结束时的回调
  * @default       -
  */
  onDrawEnd?: (canvas: HTMLCanvasElement) => void;
}

const props = withDefaults(defineProps<IProps>(), {
    // width: 350,
    // height: 550,
    width: window.innerWidth,
    height: window.innerHeight - 200,
    lineWidth: 4,
    // strokeColor: 'var(--background)',
    strokeColor: '#b2a06e',
    lineCap: 'round',
    lineJoin: 'round',
    // bgColor: '#364276',
    bgColor: '#9f3124',
    showBtn: true
});

const {
    width,
    height,
    lineWidth,
    strokeColor,
    lineCap,
    lineJoin,
    bgColor,
    showBtn,
    onSave,
    onClear,
    onDrawEnd
} = props;

const canvasRef = ref<any>(null);
const ctxRef = ref<any>(null);

// 保存上次绘制的 坐标及偏移量
const client = ref<any>({
    offsetX: 0, // 偏移量
    offsetY: 0,
    endX: 0, // 坐标
    endY: 0
})

// 判断是否为移动端
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent));


// 取消-清空画布
const cancel = () => {
    handleClick('1')
    // 清空当前画布上的所有绘制内容
    if (canvasRef.value) {
        const canvasCtx = canvasRef.value.getContext("2d")
        canvasCtx.clearRect(0, 0, width, height)
        onClear && onClear(canvasRef.value)
        
        initCanvas()
    }
}

// 保存-将画布内容保存为图片
const save = () => {
    handleClick('2')
    showConfirmDialog({
        title: '',
        confirmButtonColor: '#bca1f3',
        message: '确定要保存下来吗？',
    })
    .then(() => {
        // 将canvas上的内容转成blob流
        canvasRef.value.toBlob((blob: any) => {
        // 获取当前时间并转成字符串，用来当做文件名
        const date = Date.now().toString()
        // 创建一个 a 标签
        const a = document.createElement('a')
        // 设置 a 标签的下载文件名
        a.download = `手写板${date}.png`
        // 设置 a 标签的跳转路径为 文件流地址
        a.href = URL.createObjectURL(blob)
        // 手动触发 a 标签的点击事件
        a.click()
        // 移除 a 标签
        a.remove()
        onSave && onSave(blob)
        })
    })
}

// 绘制
const draw = (event: { changedTouches?: any; pageX?: any; pageY?: any; }) => {
    // 获取当前坐标点位
    const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
    // 获取canvas 实例
    const canvas: HTMLCanvasElement = canvasRef.value as any;

    const { x, y } = canvas.getBoundingClientRect();
    // 修改最后一次绘制的坐标点
    client.value.endX = pageX
    client.value.endY = pageY
    // 根据坐标点位移动添加线条
    ctxRef.value.lineTo(pageX - x, pageY - y)
    // 绘制
    ctxRef.value.stroke()
}

// 初始化
const init = (event: { changedTouches?: any; offsetX?: any; offsetY?: any; pageX?: any; pageY?: any; }) => {
    // 获取偏移量及坐标
    const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
    const canvas: HTMLCanvasElement = canvasRef.value as any
    
    const { x, y } = canvas.getBoundingClientRect()

    client.value.offsetX = offsetX
    client.value.offsetY = offsetY
    client.value.endX = pageX
    client.value.endY = pageY

    // 清除以上一次 beginPath 之后的所有路径，进行绘制
    ctxRef.value.beginPath()
    // 根据配置文件设置相应配置
    ctxRef.value.lineWidth = lineWidth
    ctxRef.value.strokeStyle = strokeColor
    ctxRef.value.lineCap = lineCap
    ctxRef.value.lineJoin = lineJoin
    // 设置画线起始点位
    ctxRef.value.moveTo(client.value.endX - x, client.value.endY - y)
    // 监听 鼠标移动或手势移动
    window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
}

// 结束绘制
const closeDraw = () => {
    console.log(ctxRef.value)
    // 结束绘制
    ctxRef.value.closePath()
    // 移除鼠标移动或手势移动监听器
    window.removeEventListener("mousemove", draw)
    onDrawEnd && onDrawEnd(canvasRef.current)
}

const initCanvas = () => {
    // 获取canvas 实例
    const canvas: HTMLCanvasElement = canvasRef.value as any
    // 设置宽高
    canvas.width = width;
    canvas.height = height;
    // 创建上下文
    const ctx: any = canvas.getContext('2d')
    ctxRef.value = ctx;
    // 设置填充背景色
    ctxRef.value.fillStyle = bgColor
    // 绘制填充矩形
    ctxRef.value.fillRect(
        0, // x 轴起始绘制位置
        0, // y 轴起始绘制位置
        width, // 宽度
        height // 高度
    )
}

const addEventListener = () => {
    // 创建鼠标/手势按下监听器
    window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
    // 创建鼠标/手势 弹起/离开 监听器
    window.addEventListener(mobileStatus ? "touchend" : "mouseup", closeDraw)
}

const removeEventListener = () => {
    // 创建鼠标/手势按下监听器
    window.removeEventListener(mobileStatus ? "touchstart" : "mousedown", init)
    // 创建鼠标/手势 弹起/离开 监听器
    window.removeEventListener(mobileStatus ? "touchend" : "mouseup", closeDraw)
}

const initEsign = () => {
    initCanvas()
    addEventListener()
}

onMounted(() => {
    initEsign()
    showNotify({
        message: '因系统差异IOS等部分机型需长按屏幕即可书写',
        color: '#FFFFFF',
        background: '#bca1f3',
        duration: 2500, // 持续时间，单位为毫秒
        position: 'top', // 位置，可以是 'top'、'bottom'、'top-left'、'top-right'、'bottom-left'、'bottom-right'
    });
})

onUnmounted(() => {
    removeEventListener()
})

</script>


<style lang="scss" scoped>
.writeContent {
    width: 100vw;
    height: 100vh;
    padding: 0 15px;
    position: fixed;
    top: 0;
    left: 0;
    overflow: hidden;
    .writeBtn {
        width: 100%;
        height: 50px;
        padding: 0 15px;
        position: fixed;
        left: 0;
        top: 70px;
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: space-around;
        .active {
            // background-color: blue; /* 改变背景颜色 */
            transform: scale(1.1); /* 放大按钮 */
        }
    }
    .writeBox {
        margin-top: 140px;
        width: 100%;
        height: auto;
        overflow: hidden;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}
</style>